package utils

import (
	"GoTime/utils/conf"
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"crypto/x509"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/spf13/cast"
	"golang.org/x/crypto/pkcs12"
)

// GetSignURL 获取签名地址
func GetSignURL(funcname string, data map[string]interface{}, reqtype int64, province, city string) (string, error) {
	var (
		body []byte
		err  error
	)
	if data == nil {
		params := strings.Split(funcname, "-")
		if len(params) == 2 {
			return Encrypt(funcname, []byte(params[1]), reqtype, province, city)
		} else if len(params) == 3 {
			return Encrypt(funcname, []byte(params[0]+params[2]), reqtype, province, city)
		} else if len(params) == 4 {
			return Encrypt(funcname, []byte(params[0]+params[2]+params[3]), reqtype, province, city)
		}
	} else if body, err = json.Marshal(data); err != nil {
		return "", err
	} else {
		return Encrypt(funcname, body, reqtype, province, city)
	}
	return "", errors.New("生成请求地址失败 " + funcname)
}

// Encrypt 生成签名地址
func Encrypt(funcname string, data []byte, reqtype int64, province, city string) (string, error) {
	var (
		headurl      string //三方请求地址
		serialnumber int64
		hashed       []byte
		signed       []byte
		key          *rsa.PrivateKey
		err          error
		certPath     string
		certPass     string
		encryptVer   string
	)
	//log.Println(province)
	//获取省平台地址和全国驾培平台地址
	if reqtype == 1 {
		headurl = conf.GetString(province + ".country_url")

	} else if reqtype == 3 {
		headurl = conf.GetString(province + ".city_url")
	} else {
		headurl = conf.GetString(province + ".province_url")

	}
	//log.Println(headurl)
	certPath = conf.GetString(province + ".cert_key")
	certPass = conf.GetString(province + ".cert_pass")
	encryptVer = conf.GetString(province + ".encrypt_ver")
	//log.Println(encryptVer, certPath, certPass)
	if province == "420000" && reqtype == 3 {
		certPath = "certificate/shandongwangzheng.pfx"
	}
	if key, serialnumber, err = readPrivateKey(certPath, certPass); err != nil {
		return "", err
	}
	// 时间戳
	var timestamp int64
	if province == "420000" {
		if city == "420100" {
			timestamp = time.Now().UnixNano() / 1e6
		} else {
			timestamp = 1460781298504
		}
	} else {
		timestamp = time.Now().UnixNano() / 1e6
	}

	// 第一步  加密数据hash运算
	if hashed = getDataHash(data, timestamp, encryptVer); hashed == nil {
		return "", errors.New("计算校验和失败")
	}
	// 第二步 进行rsa加密签名--私钥加密
	if signed, err = rsa.SignPKCS1v15(rand.Reader, key, 0, hashed); err != nil {
		return "", err
	}
	// 第三步 hex编码
	signStr := strings.ToUpper(hex.EncodeToString(signed))
	if province == "420000" {
		return fmt.Sprintf("%s%s?v=%s&ts=%d&sign=%s&user=%X", headurl, funcname, encryptVer, timestamp, signStr, serialnumber), nil
	}
	return fmt.Sprintf("%s%s?v=%s&ts=%d&sign=%s&user=%x", headurl, funcname, encryptVer, timestamp, signStr, serialnumber), nil
}

// readPrivateKey 读取pfx文件中的私钥
func readPrivateKey(filename, password string) (*rsa.PrivateKey, int64, error) {
	var (
		pfxData []byte
		key     interface{}
		cert    *x509.Certificate
		err     error
	)
	fmt.Println("读取私钥")
	fmt.Println(filename)
	if pfxData, err = ioutil.ReadFile(filename); err != nil {
		return nil, 0, err
	}
	if key, cert, err = pkcs12.Decode(pfxData, password); err != nil {
		return nil, 0, err
	}
	privateKey := key.(*rsa.PrivateKey)
	if err = privateKey.Validate(); err != nil {
		return nil, 0, err
	}
	return privateKey, cert.SerialNumber.Int64(), nil
}

// getDataHash 计算数据校验返回hash值
func getDataHash(data []byte, timestamp int64, method string) []byte {
	var hash hash.Hash
	switch method {
	case "1.0.0.e1":
		hash = sha1.New()
	case "1.0.0.e2":
		hash = sha256.New()
	case "1.0.0.e3":
		hash = sha512.New()
	default:
		hash = sha256.New()
	}

	buf := bytes.NewBuffer(data)
	// 大端写入时间戳
	binary.Write(buf, binary.BigEndian, timestamp)
	// 计算校验和
	hash.Write(buf.Bytes())
	return hash.Sum(nil)
}

// APIReq 接口请求
func APIReq(url string, data map[string]interface{}, method string) (map[string]interface{}, error) {
	var (
		jsondata []byte
		body     []byte
		request  *http.Request
		response *http.Response
		err      error
	)
	if jsondata, err = json.Marshal(data); err != nil {
		return nil, err
	}
	if request, err = http.NewRequest(method, url, bytes.NewBuffer(jsondata)); err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/json; charset=UTF-8")
	if response, err = http.DefaultClient.Do(request); err != nil {
		return nil, err
	}
	//*注意关闭流
	defer response.Body.Close()
	if body, err = ioutil.ReadAll(response.Body); err != nil {
		return nil, err
	}
	fmt.Print(string(body), "body")
	// 记录数据库
	// (&m.ApiLog{
	// 	Url:    url,
	// 	Method: method,
	// 	Param:  string(jsondata),
	// 	Result: string(body)}).Add()

	retMap := make(map[string]interface{})
	fmt.Println("请求参数", string(jsondata), "请求地址：", url, "返回结果", string(body))
	if err = json.Unmarshal(body, &retMap); err != nil {
		return nil, err
	}
	return retMap, nil
}

// FileId 上传文件
func FileId(uri, imgtype string, reqtype int64, province, city string) (string, error) {
	//根据id查询图片
	var (
		f      io.ReadCloser
		client *oss.Client
		bucket *oss.Bucket
		u      *url.URL
		id     float64
		err    error
	)
	// 上传到oss
	if client, err = oss.New(conf.GetString("oss.endpoint"), conf.GetString("oss.access_id"), conf.GetString("oss.access_key")); err != nil {
		return "0", err
	}
	if bucket, err = client.Bucket(conf.GetString("oss.bucket")); err != nil {
		return "0", err
	}

	fmt.Println("ccccccccc")
	if u, err = url.Parse(uri); err != nil {
		return "0", err
	}
	fmt.Println("dddddddddd")
	fmt.Println(u)
	fmt.Println(u.Path[1:])
	if f, err = bucket.GetObject(u.Path[1:]); err != nil {
		return "0", err
	}
	fmt.Println("eeeeeeeeeee")

	defer f.Close()
	fmt.Print(uri, "uri")
	if province == "520000" {
		//var idGuizhou string
		//if idGuizhou, _, err = GuizhouImageup(f, imgtype, u.Path[1:], reqtype, province, city); err != nil {
		//	return "0", err
		//}
		return "0", nil
	} else {
		if id, _, err = ImageUp(f, imgtype, u.Path[1:], reqtype, province, city); err != nil {
			return "0", err
		}
		return fmt.Sprintf("%.f", id), nil
	}

}

// ImageUp  文件上传
func ImageUp(f io.Reader, imgtype, filename string, reqtype int64, province, city string) (float64, []byte, error) {
	var (
		part     io.Writer
		rsp      *http.Response
		data     []byte
		ret_byte []byte
		uri      string
		err      error
		id       float64
	)
	if data, err = ioutil.ReadAll(f); err != nil {
		return 0, nil, err
	}
	fmt.Println("asdasdasd")
	if uri, err = Encrypt("imageup/"+imgtype, data, reqtype, province, city); err != nil {
		return 0, data, err
	}
	fmt.Println("!@!!!!!!")
	body := bytes.NewBuffer(nil)
	writer := multipart.NewWriter(body)
	if part, err = writer.CreateFormFile("file", filename); err != nil {
		return 0, data, err
	}
	fmt.Println("@@@@@###")
	part.Write(data)
	writer.Close()
	fmt.Println(uri)
	// fmt.Println(writer.FormDataContentType())
	// fmt.Println(body)
	if rsp, err = http.Post(uri, writer.FormDataContentType(), body); err != nil {
		return 0, data, err
	}
	defer rsp.Body.Close()
	if ret_byte, err = ioutil.ReadAll(rsp.Body); err != nil {
		fmt.Println(err.Error())
		return 0, data, err
	}
	fmt.Println(string(ret_byte), "1111111111111111111111")
	ret_map := make(map[string]interface{})
	if err = json.Unmarshal(ret_byte, &ret_map); err != nil {
		fmt.Println(err.Error())
		return 0, data, errors.New("监管平台服务异常")
	}
	fmt.Println("解析为json")
	fmt.Println(ret_map)
	switch ret_map["errorcode"].(type) {
	case float64:
		if ret_map["errorcode"].(float64) != 0 {
			return 0, data, errors.New(ret_map["message"].(string))
		}
	case string:
		if ret_map["errorcode"].(string) != "0" {
			return 0, data, errors.New(ret_map["message"].(string))
		}
	}
	if md, ok := ret_map["data"].(map[string]interface{}); ok {
		switch md["id"].(type) {
		case float64:
			fmt.Println(md["id"], "~~~~~~~~~~~~~~~~~~~~~~", md["id"].(float64))
			return md["id"].(float64), data, nil
		case string:
			id, _ = strconv.ParseFloat(md["id"].(string), 64)
			return id, data, nil
		}

	}
	return 0, data, errors.New("获取文件编号失败")
}

// CertImageUp &风采文件上传
func CertImageUp(fileURL string, imageType int, bussno string, province, city string) (string, error) {
	var (
		url     string
		ret_map map[string]interface{}
		err     error
	)
	if fileURL == "" {
		return "", nil
	}
	data := map[string]interface{}{
		"platnum": "A0033",
		"picno":   cast.ToString(time.Now().Unix()),
		"type":    imageType,
		"bussno":  bussno,
		"fileurl": fileURL,
		"size":    2,
		"flag":    1,
	}
	if url, err = GetSignURL("CertImageup", data, 2, province, city); err != nil {
		//Resp(c, 201, ret_map["message"].(string), nil)
		return ret_map["message"].(string), err
	}
	ret_map, err = APIReq(url, data, "POST")
	log.Println(ret_map, err)
	return "", nil
}
